package com.yfqy.admin.conf.Idgenerator;

import com.yfqy.admin.constant.MyConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;

/**
 * 分布式ID生成器 (基于Snowflake算法)
 * 作为Spring Bean管理，支持自动配置workerId
 */
@Component
public class SnowflakeIdGenerator {

    private static final Logger LOGGER = LoggerFactory.getLogger(SnowflakeIdGenerator.class);

    // 起始时间戳 (2020-01-01)
    private final static long START_TIMESTAMP = 1577808000000L;

    // 各部分位数
    private final static long WORKER_ID_BITS = MyConstants.L10;
    private final static long SEQUENCE_BITS = MyConstants.L12;

    // 最大值
    private final static long MAX_WORKER_ID = ~(MyConstants._L1 << WORKER_ID_BITS);
    private final static long MAX_SEQUENCE = ~(MyConstants._L1 << SEQUENCE_BITS);

    // 移位
    private final static long WORKER_ID_SHIFT = SEQUENCE_BITS;
    private final static long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;

    private final long workerId;
    private long sequence = MyConstants.L0;
    private long lastTimestamp = MyConstants._L1;

    /**
     * 构造函数(由Spring注入workerId)
     */

    /**
     * 私有构造函数
     */
    private SnowflakeIdGenerator(@Value("${yfqy.id-generator.workerId:}") Long workerId) {
        LOGGER.debug("私有SnowflakeIdGenerator构造函数,workerId={}", workerId);
        if (workerId == null) {
            workerId = generateAutoWorkerId();
        }
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException(
                    String.format("Worker ID can't be greater than %d or less than 0", MAX_WORKER_ID));
        }
        this.workerId = workerId;
    }

    /**
     * 生成下一个ID (线程安全)
     */
    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
                            lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
                | (workerId << WORKER_ID_SHIFT)
                | sequence;
    }

    /**
     * 自动生成workerId
     */
    private static long generateAutoWorkerId() {
        try {
            NetworkInterface network = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
            byte[] mac = network.getHardwareAddress();
            int macHash = mac != null ? Math.abs(new String(mac).hashCode()) : 0;

            String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
            int pidHash = Math.abs(pid.hashCode());

            return (macHash + pidHash) % (MAX_WORKER_ID + 1);
        } catch (Exception e) {
            return (long) (Math.random() * MAX_WORKER_ID);
        }
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    // 解析方法保持不变
    public static long parseTimestamp(long id) {
        return (id >> TIMESTAMP_SHIFT) + START_TIMESTAMP;
    }

    public static long parseWorkerId(long id) {
        return (id >> WORKER_ID_SHIFT) & MAX_WORKER_ID;
    }

    public static long parseSequence(long id) {
        return id & MAX_SEQUENCE;
    }
}